<?php
/**
 * @author jonathan <jo.link.noir@gmail.com>
 * @version 1.0: jo_link_noir
 * @date 31-05-2010
 *
 * @description Cette classe définit un algorithme de résolution de dépendance pour les structures. le format des dependance est le suivant
	{['structures' => {nameStruct => {group => lvlMin, …}, …}],
	'groups' => {
		{idGroup =>
			['race' => int], (optionel, default = all)
			['required' => boolean], (optionel, default = false)
			['multiple' => {
				{
					['race' => int],
					['required' => true]
					['structures' => {
						nameStruct => {group => lvlMin, …}, …
					}]
					['multiple'] => …
				}, …
			}]
			['structures' => {nameStruct => {group => lvlMin, …}, …}]
		}, …
	}}
	Si structure n'est pas définit on peut directement mettre le tableau de 'groups'. Si structures est seul alors il n'y a pas besoin de le préciser.
 */
class SW_Structure_Dependency extends SW_Dependency
{
	/** @var SW_Structure_Dependency_Tree*/
	protected $dependencyTree;

	/** @var array : {SW_Structure, …} instance des structures*/
	private $_structures;

	/** @var SW_Structure passé en paramètre de solve*/
	protected $structure;

	/** @var int*/
	protected $race;


	/**
	 * @param SW_Structure_Dependency_Tree $dependencyTree
	 */
	public function __construct(SW_Structure_Dependency_Tree $dependencyTree)
	{
		$this->dependencyTree = $dependencyTree;
	}


	/**
	 * Crée un tableau des dépendance
	 * @param SW_Planet_Storage_Treatment $structure
	 */
	protected function solve(SW_Planet_Storage_Treatment $structure)
	{
		$this->structure = $structure;
		$this->race = $structure->getPlayer()->getRace();
		$this->required = $this->unblock = array();
		$this->_structures = array($structure->__toString() => $structure);

		$structuresTree = $this->dependencyTree->getStructures();
		if ($structuresTree && !$this->checkStructure($structuresTree))
		{
			foreach ($this->dependencyTree->getGroups() as $group => $dependency)
				if (isset($dependency['required']) && $dependency['required'])
					$this->required[$group] = $group;
		}
		else
		{
			foreach ($this->dependencyTree->getGroups() as $group => $dependency)
			{
				if ($this->checkDependency($dependency))
					$this->unblock[$group] = $group;
				elseif (isset($dependency['required']) && $dependency['required'])
					$this->required[$group] = $group;
			}
		}
	}

	final protected function getStructureDependency($index)
	{
		return isset($this->_structures[$index])
			? $this->_structures[$index]
			: $this->_structures[$index] = $this->structure->getSiblingInstance($index);
	}

	/**
	 * @param array|Traversable $treeStructures
	 * @return bool
	 */
	protected function checkStructure($treeStructures)
	{
		foreach (isset($treeStructures['structures'])
			? $treeStructures['structures']
			: $treeStructures
			as $indexStruct => $dependency)
		{
			if (!$this->checkLevel($this->getStructureDependency($indexStruct), $dependency))
				return false;
		}
		return true;
	}

	/**
	 * @param SW_Structure $structure
	 * @param array|Traversable $dependency : {$group => $levelMin, …}
	 * @return bool
	 */
	protected function checkLevel(SW_Structure $structure, $dependency)
	{
		if (!is_array($dependency) && !($dependency instanceof Iterator))
			var_dump($dependency);
		foreach ($dependency as $group => $level)
			if ($structure->getLevelMaxGroup($group) < $level)
				return false;
		return true;
	}

	/**
	 * @param true|array|Traversable $dependency
	 * @return bool
	 */
	protected function checkDependency($dependency)
	{
		if (true === $dependency)
			return true;
		else if (isset($dependency['race']) && !$this->race === $dependency['race'])
			return false;
		else if (isset($dependency['multiple']))
		{
			foreach ($dependency['multiple'] as $m_dependency)
			{
				if ($this->checkDependency($m_dependency))
					return true;
			}
			return false;
		}
		else
			return $this->checkStructure($dependency);
	}
}